/**
 * 
 */
package com.flashdeck.utils;


/**
 * Not thread safe
 * @author Vincentas
 *
 */
public class InputStreamLimit extends InputStream {

	private final InputStream inputStream;
	
	private final long limit;
	
	private long read = 0;
	
	private long readWhenMarked = 0;
	
	public InputStreamLimit(InputStream inputStream, long limit) {
		this.inputStream = inputStream;
		this.limit = limit;
	}
	
	/* (non-Javadoc)
	 * @see java.io.InputStream#read()
	 */
	@Override
	public int read() throws IOException {
		if (read < limit) {
			read++;
			return inputStream.read();
		} else {
			return -1;
		}
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#available()
	 */
	@Override
	public int available() throws IOException {
		return (int) Math.min(inputStream.available(), limit - read);
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#close()
	 */
	@Override
	public void close() throws IOException {
		inputStream.close();
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#mark(int)
	 */
	@Override
	public void mark(int readlimit) {
		readWhenMarked = read;
		inputStream.mark(readlimit);
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#markSupported()
	 */
	@Override
	public boolean markSupported() {
		return inputStream.markSupported();
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#read(byte[], int, int)
	 */
	@Override
	public int read(byte[] b, int offset, int length) throws IOException {
		return increment(inputStream.read(b, offset, Math.min(length, available())));
	}
	
	private int increment(int value) {
		if (value != -1) {
			read += value;
		}
		
		if (value == 0) {
			value = -1;
		}
		
		return value;
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#read(byte[])
	 */
	@Override
	public int read(byte[] b) throws IOException {
		int available = available();
		if (b.length > available) {
			return read(b, 0, available);
		} else {
			return increment(inputStream.read(b));
		}
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#reset()
	 */
	@Override
	public synchronized void reset() throws IOException {
		inputStream.reset();
		read = readWhenMarked;		
	}

	/* (non-Javadoc)
	 * @see java.io.InputStream#skip(long)
	 */
	@Override
	public long skip(long n) throws IOException {
		n = Math.min(n, limit - read);
		long result = inputStream.skip(n);
		read += result;
		return result;
	}
}
